
//-------- MESSAGE ID CONSTANTS ---------

// System
const CHANGE_SYSTEM_STATUS = 1000;
const PUT_SYSTEM_STATUS = 1001;

// Train Initialization
const DO_INIT_TRAIN = 1002;
const PUT_INIT_TRAIN = 1003;

const CHANGE_POWER_STATUS = 1004;
//const PUT_SYSTEM_STATUS = 1001;

// Throttle
const OPEN_THROTTLE_REQUEST = 1050;
const OPEN_THROTTLE_RESPONSE = 1051;
const CLOSE_THROTTLE = 1052;

const PUT_AVAILABLE_TRAINS = 1099;

// Response is a PUT_TRAIN_INFO
const SET_TRAIN_SPEED = 1100;
const SET_TRAIN_DIRECTION = 1102;
const SET_TRAIN_LIGHT = 1104;
const SET_TRAIN_HORN = 1106;
const SET_TRAIN_BELL = 1108;
const SET_TRAIN_MUTE = 1110;

// Response is a PUT_SWITCH delivered to switch layout(s)
const SET_TRAIN_NEXT_SWITCH = 1112; 

const PUT_TRAIN_INFO = 1151;
const PUT_TRAIN_STATE = 1153;

const SET_SWITCH = 1200;
const PUT_SWITCH = 1201; // Single switch
const GET_SWITCHES = 1202 //Response is PUT_SWITCHES
const PUT_SWITCHES = 1203; // ALL switches in an array
const OPEN_SWITCHES_REQUEST = 1210
const OPEN_SWITCHES_RESPONSE = 1211
const CLOSE_SWITCHES_REQUEST = 1212 //client closed switches page
const CLOSE_SWITCHES = 1213 //Server is closing switches

// Other
const WELCOME_MESSAGE = 1999; // Provides the client with their authenticated user name

// -------- MESSAGE FIELD CONSTANTS (ENUMERATIONS) ---------

// System status
const SYSTEM_STATUS_STOPPED = 0;
const SYSTEM_STATUS_RUNNING = 1;
const SYSTEM_STATUS_STARTING = 2;
const SYSTEM_STATUS_STOPPING = 3;

// Switch states
const SWITCH_CLOSED = 0;
const SWITCH_THROWN = 1;
const SWITCH_BEGIN_CLOSED = 2;
const SWITCH_BEGIN_THROWN = 3;
const SWITCH_UNKNOWN = 4;

//Switch types
const SWITCH_SIMPLE = 0;
const SWITCH_VISUAL = 1;
const SWITCH_EMERGENCY = 2;

// Train direction
const DIRECTION_FORWARD = 0;
const DIRECTION_BACKWARD = 1;

// Basic ON/OFF - for HORN, LIGHTS, and MUTE fields
const STATE_OFF = 0;
const STATE_ON = 1;

// Train state
const TRAIN_STATE_MOVING = 0;
const TRAIN_STATE_WAITING = 1;
const TRAIN_STATE_HALTED = 2;
const TRAIN_STATE_ERROR = 3;
const TRAIN_STATE_BEGIN_CHANGE_DIRECTION = 4;
const TRAIN_STATE_BEGIN_WAITING = 5;
const TRAIN_STATE_BEGIN_HALTED = 6;

// Train availability status
const TRAIN_UNINITIALIZED = 0;
const TRAIN_TAKEN_BASIC = 1;
const TRAIN_TAKEN_DIRECT = 2;
const TRAIN_AVAILABLE = 3;

// Prevents the throttle div from being resized more than once
// (to prevent "home page growing" glitch every time train is init'ed)
var trainDivSizeSet = false;

//-------- MESSAGE CLASSES ---------

function ChangeSystemStatus(systemStatus) {
	this.id = CHANGE_SYSTEM_STATUS;
	this.systemStatus = systemStatus;
}

function ChangePowerStatus(onOffState) {
	this.id = CHANGE_POWER_STATUS;
	this.onOffState = onOffState;
}

function DoInitializeTrain(trainId, headSensor, tailSensor) {
	this.id = DO_INIT_TRAIN;
	this.trainId = trainId;
	this.headSensor = headSensor;
	this.tailSensor = tailSensor;
}

function OpenThrottleRequest(trainId, direct) {
	this.id = OPEN_THROTTLE_REQUEST;
	this.trainId = trainId;
	this.direct = direct;
}

function CloseThrottle(trainId) {
	this.id = CLOSE_THROTTLE;
	this.trainId = trainId;
}

function SetTrainSpeed(trainId, speed) {
	this.id = SET_TRAIN_SPEED;
	this.trainId = trainId;
	this.speed = speed;
}

function SetTrainDirection(trainId, direction) {
	this.id = SET_TRAIN_DIRECTION;
	this.trainId = trainId;
	this.direction = direction;
}

function SetTrainLight(trainId, light) {
	this.id = SET_TRAIN_LIGHT;
	this.trainId = trainId;
	this.light = light;
}

function SetTrainHorn(trainId, horn) {
	this.id = SET_TRAIN_HORN;
	this.trainId = trainId;
	this.horn = horn;
}

function SetTrainBell(trainId, bell) {
	this.id = SET_TRAIN_BELL;
	this.trainId = trainId;
	this.bell = bell;
}

function SetTrainMute(trainId, mute) {
	this.id = SET_TRAIN_MUTE;
	this.trainId = trainId;
	this.mute = mute;
}

function SetTrainNextSwitch(trainId, closeOrThrow) {
	this.id = SET_TRAIN_NEXT_SWITCH;
	this.trainId = trainId;
	this.closeOrThrow = closeOrThrow;
}

function OpenSwitchRequest(isEmergency, switchType)
{
	this.id = OPEN_SWITCHES_REQUEST;
	this.isEmergency = isEmergency;
	this.switchType = switchType;
}

function CloseSwitchesRequest()
{
	this.id = CLOSE_SWITCHES_REQUEST;
}

function SetSwitch(switchId) {
	this.id = SET_SWITCH;
	this.switchId = switchId;
}

function GetSwitches()
{
	this.id = GET_SWITCHES;
}

//-------- GLOBAL FIELDS & METHODS ---------

var isConnected = false;

if (!window.WebSocket) {
	window.WebSocket = window.MozWebSocket;
	if (!window.WebSocket)
		alert("WebSocket not supported by this browser");
}

// An object that houses a WebSocket connection. Provides methods for receiving
// and sending messages.
var conn = {
	// Creates the WebSocket connection.
	connect : function() {
		this.throttles = {};
		this.switchesPages = new Array();
		var loc = document.location;
		var location = loc.protocol.replace('http', 'ws') + "//" + loc.host + "/rwt/rail";
		this._ws = new WebSocket(location, "rail");
		this._ws.onopen = this.onopen;
		this._ws.onmessage = this.onmessage;
		this._ws.onclose = this.onclose;
	},

	// Sends a message to the server (using the established WebSocket).
	send : function(message) {
		if (this._ws) {
			var messageText;
			if (message.id) {
				messageText = JSON.stringify(message);
			} else {
				messageText = message;
			}
			this._ws.send(messageText);
		}
	},

	// Closes the WebSocket connection.
	close : function() {
		this._ws.close();
	},

	// Called when the connection is first opened.
	onopen : function() {
		window.top.conn.send('[join]');
	},

	// Called whenever a message is received from the server through the WebSocket.
	onmessage : function(m) {
		var text = m.data;
		if (text) {
			if (text == '[marco]') {
				window.top.conn.send('[polo]');
			} else {
				var obj = JSON.parse(text);
				switch (obj.id) {
				case WELCOME_MESSAGE:
					handleWelcomeMessage(obj);
					break;
				case PUT_SYSTEM_STATUS:
					handlePutSystemStatus(obj);
					break;
				case PUT_INIT_TRAIN:
					handlePutInitTrain(obj);
					break;
				case PUT_AVAILABLE_TRAINS:
					handlePutAvailableTrains(obj);
					break;
				case OPEN_THROTTLE_RESPONSE:
					handleOpenThrottleResponse(obj);
					break;
				case OPEN_SWITCHES_RESPONSE:
					handleOpenSwitchResponse(obj);
					break;
				case CLOSE_SWITCHES:
					handleCloseSwitches();
					break;
				case PUT_SWITCH:
					handlePutSwitch(obj);
					break;
				case PUT_SWITCHES:
					handlePutSwitches(obj)
				default:
					if (obj.trainId) {
						var throttle = window.top.conn.throttles[obj.trainId.toString()];
						if (throttle) {
							throttle.handleMessage(obj);
						}
					}
				}
			}
		}
	},

	// Called when the WebSocket is closed.
	onclose : function(m) {
		this._ws = null;
	},
	
	addThrottle : function(throttle) {
		this.throttles[throttle.trainId.toString()] = throttle;
	},
	
	addSwitches : function(switches) {
		this.switchesPages.push(switches);
	}
};

function Throttle(_trainId, _handleMessageCallback, _emergency) {
	this.trainId = _trainId;
	this.handleMessage = _handleMessageCallback;
	this.isStopped = true;
	this.emergency = _emergency;
	
	this.speed = 0;
	this.direction = DIRECTION_FORWARD;
	this.light = STATE_OFF;
	this.horn = STATE_OFF;
	this.bell = STATE_OFF;
	this.mute = STATE_OFF;
	
	window.top.conn.addThrottle(this);
}

Throttle.prototype.setSpeed = function(speed) {
	var msg = new SetTrainSpeed(this.trainId, speed);
	window.top.conn.send(msg);
}

Throttle.prototype.toggleDirection = function() {
	var msg = new SetTrainDirection(this.trainId, 1 - this.direction);
	window.top.conn.send(msg);
}

Throttle.prototype.toggleLight = function() {
	var msg = new SetTrainLight(this.trainId, 1 - this.light);
	window.top.conn.send(msg);
}

Throttle.prototype.blowHorn = function() {
	var msg = new SetTrainHorn(this.trainId, STATE_ON);
	window.top.conn.send(msg);
}

Throttle.prototype.stopHorn = function() {
	var msg = new SetTrainHorn(this.trainId, STATE_OFF);
	window.top.conn.send(msg);
}

Throttle.prototype.toggleBell = function() {
	var msg = new SetTrainBell(this.trainId, 1 - this.bell);
	window.top.conn.send(msg);
}

Throttle.prototype.toggleMute = function() {
	var msg = new SetTrainMute(this.trainId, 1 - this.mute);
	window.top.conn.send(msg);
}

Throttle.prototype.setNextSwitch = function(closeOrThrow) {
	var msg = new SetTrainNextSwitch(this.trainId, closeOrThrow);
	window.top.conn.send(msg);
}

//Controls switches page
function Switches(_handleMessageCallback)
{
	this.handleMessage = _handleMessageCallback;
	window.top.conn.addSwitches(this);
	var msg = new GetSwitches();
	window.top.conn.send(msg);
}

Switches.prototype.changeSwitch = function(switchId)
{
	var msg = new SetSwitch(switchId);
	window.top.conn.send(msg);
}

// CLIENT -> SERVER

function startSystem() {
	var msg = new ChangeSystemStatus(SYSTEM_STATUS_RUNNING);
	window.top.conn.send(msg);
}

function stopSystem() {
	var msg = new ChangeSystemStatus(SYSTEM_STATUS_STOPPED);
	window.top.conn.send(msg);
}

function powerOn() {
	var msg = new ChangePowerStatus(STATE_ON);
	window.top.conn.send(msg);
}

function powerOff() {
	var msg = new ChangePowerStatus(STATE_OFF);
	window.top.conn.send(msg);
}

function initTrain(trainId) {
	var headSensor = parseInt($('#headSensorTrain' + trainId).val());
	var tailSensor = parseInt($('#tailSensorTrain' + trainId).val());
	var msg = new DoInitializeTrain(trainId, headSensor, tailSensor);
	window.top.conn.send(msg);
}

// SERVER -> CLIENT

function handleWelcomeMessage(obj) {
	window.top.userName = obj.userName;
}

function handlePutSystemStatus(obj) {
	var text;
	var color;
	var switchStatus = obj.systemStatus;
	var running = false;
	
	if (switchStatus == SYSTEM_STATUS_STOPPED) {
		text = "Stopped";
		color = 'red';
	} else if (switchStatus == SYSTEM_STATUS_RUNNING) {
		text = "Running";
		color = 'green';
		running = true;
	} else if (switchStatus == SYSTEM_STATUS_STARTING) {
		text = "Starting...";
		color = 'blue';
	} else if (switchStatus == SYSTEM_STATUS_STOPPING) {
		text = "Stopping...";
		color = 'blue';
	} else {
		text = "Unknown";
		color = 'red';
	}
	
	var displayValue = (running ? 'block' : 'none');
	$('#train_section').css('display', displayValue);
	$('#switch_section').css('display', displayValue);
	
	$('#lblSystemStatus').html(text);
	$('#lblSystemStatus').css('color', color);
}

function handlePutInitTrain(obj) {
	var doc = frames["if_initialize_trains"].document;
	var btnTrain =  doc.getElementById("btnTrain" + obj.trainId);
	var divTrain = doc.getElementById("divTrain" + obj.trainId);
	
	if (obj.succeeded) {
		btnTrain.value = "Modify";
		divTrain.setAttribute("state", "initialized");
	} else {
		btnTrain.value = "Initialize";
		divTrain.setAttribute("state", "error");
		alert("We're sorry.  That train could not be initialized.\n\nServer says:   \"" + obj.reason + "\"");
	}
}

function handlePutAvailableTrains(obj) {
	$("#div_throttles").html("");
	
	window.top.availTrains = obj; // Save so we can use it elsewhere
	
	var isEmer = window.top.emergency_mode;
	if (typeof emergency_mode != 'undefined' && emergency_mode == true)
		isEmer = true;
	
	for (var trainId in obj.trainStates) {
		var state = obj.trainStates[trainId];
		var disabledText = ' '; 
		if (!isEmer) // No throttle button is disabled in emergency mode
			disabledText = (obj.trainStates[trainId] == TRAIN_AVAILABLE ? '' : ' disabled="disabled" ');
		
		var operator = obj.trainOperators[trainId];
		var classStr = 'button_gray';
		
		if (!isEmer) {
			if (state == TRAIN_AVAILABLE)
				classStr = 'button_green';
			else if (state == TRAIN_TAKEN_BASIC || state == TRAIN_TAKEN_DIRECT) {
				if (operator == window.top.userName)
					classStr = 'button_gold';
				else
					classStr = 'button_red';
			}
		}
		
		if (state == TRAIN_TAKEN_DIRECT) {
			if (operator != window.top.userName) {
				var basicThrottles = window.top.document.getElementsByName('basic_throttle_' + trainId);
				if (basicThrottles.length > 0) {
					for (var i = 0; i < basicThrottles.length; i++) {
						var t = basicThrottles[i];
						t.close_window();
					}
				}
			}
		}
		
		var onclick = (isEmer ? ('"EmergencyThrottle(' + trainId + ');" ') : ('"BasicThrottle(' + trainId + ');" '));
		
		var emer_onclick = '"EmergencyThrottle(' + trainId + ');" ';
//		$("#div_throttles").append('<tr><td><input type="button" class="button_gray" style="display:block; float:left; height:30px;" value="' + trainId + '" onclick=' + onclick + disabledText + ' /></td>' +
//				'<td><input type="button" class="open_emergency" title="Open an emergency (direct control) throttle" onclick=' + emer_onclick + ' /></td></tr>');
		$("#div_throttles").append('<tr><td><input type="button" class="' + classStr + '" ' +
				'style="display:block; float:left; height:30px;" value="' + trainId + '" ' + 
				'onclick=' + onclick + disabledText + ' /></td>' +
				'<td>' + operator + '</td></tr>');
	}

//	resizeTrainDiv();
}

function handleOpenThrottleResponse(obj) {
	if (obj.granted == true) {
		if (obj.emergency == true)
			openEmergencyThrottle(obj.trainId, obj.virtualAddress);
		else
			openBasicThrottle(obj.trainId, obj.virtualAddress);
	} else {
		alert("You cannot open a throttle for this train.");
	}
}

function handlePutTrainInfo(obj) {
	
}

function handleOpenSwitchResponse(obj) {
	if (obj.granted == true) {
		if (obj.switchType == SWITCH_SIMPLE)
			openSimpleSwitch();
		else if (obj.switchType == SWITCH_VISUAL)
			openVisualSwitch();
		else if(obj.switchType == SWITCH_EMERGENCY)
			openEmergencySwitch();
	} else {
		alert("Could not open switches page. An emergency switch may be opened.");
	}
}

function handleCloseSwitches()
{	
	sspages = document.getElementsByName("emergency_switch");
	pages = sspages.length
	for (var p = 0; p < pages; p++)
	{
		sspages[0].parentNode.removeChild(sspages[0]);
	}
	
	sspages = document.getElementsByName("simple_switch");
	pages = sspages.length
	for (var p = 0; p < pages; p++)
	{
		sspages[0].parentNode.removeChild(sspages[0]);
	}
	
	sspages = document.getElementsByName("visual_switch");
	pages = sspages.length
	for (var p = 0; p < pages; p++)
	{
		sspages[0].parentNode.removeChild(sspages[0]);
	}
}

function handlePutSwitch(obj) {
	for (var i = 0; i < window.top.conn.switchesPages.length; i++)
	{
		window.top.conn.switchesPages[i].handleMessage(obj);
	}
}

function handlePutSwitches(obj) {
	for (var i = 0; i < obj.switchStates.length; i++)
	{
		handlePutSwitch(obj.switchStates[i]);
	}
}

function resizeTrainDiv() {
	if (trainDivSizeSet == false) {
		trainDivSizeSet = true;
		$('div.section').each(function(){
		    // Get their parent td's height
		    var tdHeight = $(this).closest('td').height();
		
		    // Set the div's height to their parent td's height
		    $(this).height(tdHeight);
		});
	}
}

function toggleEmergency() {
	// Toggle emergency_mode boolean
	window.top.emergency_mode = !window.top.emergency_mode;
	
	// Call handler with last received "putHandleAvailableTrains"
	handlePutAvailableTrains(window.top.availTrains);
}
